package p2pcdnsim.network;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.List;

import p2pcdnsim.exception.LinkAlreadyInsertedException;
import p2pcdnsim.exception.NodeAlreadyInsertedException;
import p2pcdnsim.exception.NodeUnexistentException;


import desmoj.core.simulator.Model;
import desmoj.core.simulator.SimTime;

public class NetworkTopology {
	
	private Model owner;
	private Map<Long,RouterNode> nodes;
	private Map<String,Link> links;
	
	public NetworkTopology(Model owner) {
		this.owner = owner;
		nodes = new HashMap<Long, RouterNode>();
		links = new HashMap<String, Link>();
		LinkControl.createLinkControl(owner);
	}
	
	public void addNode(RouterNode node) throws NodeAlreadyInsertedException {
		if(nodes.containsKey(node.getNodeId())) throw new NodeAlreadyInsertedException("Node "+node.getNodeId()+" already inserted.");
		nodes.put(node.getNodeId(), node);
	}
	
	public RouterNode getNode(long id) throws NodeUnexistentException {
		if(!nodes.containsKey(id)) throw new NodeUnexistentException("Node inexistent.");
		return nodes.get(id);
	}
	
	public void addLink(Link link) throws LinkAlreadyInsertedException, NodeUnexistentException {
		if(links.containsKey(link.getLinkId())) throw new LinkAlreadyInsertedException("Link "+link.getLinkId()+" already inserted.");
		if( !( nodes.containsKey(link.getNodeFrom().getNodeId()) && (nodes.containsKey(link.getNodeTo().getNodeId())))) throw new NodeUnexistentException("Link between unexistent nodes.");
		links.put(link.getLinkId(), link);
	}
	
	public Link createLink(Model owner, long fromId, long toId, int capacity, SimTime delay, Queue queue) throws NodeUnexistentException {
		if(!nodes.containsKey(fromId)) throw new NodeUnexistentException("Node from does not exist in topology.");
		if(!nodes.containsKey(toId)) throw new NodeUnexistentException("Node to does not exist in topology.");
		
		Link link = new Link(owner, nodes.get(fromId),nodes.get(toId), capacity, delay, queue);
		nodes.get(fromId).addLink(link);
		return link;
	}
	
	public Link createLink(Model owner, long fromId, long toId, int capacity, SimTime delay) throws NodeUnexistentException {
		if(!nodes.containsKey(fromId)) throw new NodeUnexistentException("Node from does not exist in topology.");
		if(!nodes.containsKey(toId)) throw new NodeUnexistentException("Node to does not exist in topology.");
		
		Link link = new Link(owner, nodes.get(fromId),nodes.get(toId), capacity, delay);
		nodes.get(fromId).addLink(link);
		return link;
	}
	
	public void printInfo() {
		System.out.println("Number of nodes: "+nodes.size());
		System.out.println("Number of links: "+links.size());
		System.out.println("Connectivity:");
		Iterator<RouterNode> it = nodes.values().iterator();
		while(it.hasNext()) {
			RouterNode n = it.next();
			System.out.println("\tFrom node "+n.getNodeId());
			Iterator<Link> nit = n.getLinks().iterator();
			while(nit.hasNext()) {
				System.out.println("\t\tto node "+((Link)nit.next()).getNodeTo().getNodeId() );
			}
		}
	}

	public List<Link> getLinks() {
		return new ArrayList<Link>(links.values());
	}

	public Model getModel() {
		return owner;
	}

	public RouterNode[] getNodes() {
		return nodes.values().toArray(new RouterNode[nodes.size()]);
	}
}
